import 'dart:typed_data';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

/// BLE协议处理器类
/// 负责BLE通信协议的封装和处理
class BLEProtocolHandler {
  // 帧格式定义
  static const int FRAME_HEADER_CMD = 0xAA;
  static const int FRAME_HEADER_RESP = 0xBB;
  static const int FRAME_TAIL_CMD = 0x55;
  static const int FRAME_TAIL_RESP = 0x66;

  // 命令类型
  static const int CMD_TYPE_DATA = 0x01;
  static const int CMD_TYPE_FILE = 0x02;
  static const int CMD_TYPE_CONTROL = 0x03;
  static const int CMD_TYPE_TIME_SYNC = 0x04; // 新增：时间同步命令

  // 响应类型
  static const int RESP_TYPE_ACK = 0x01;
  static const int RESP_TYPE_RETRANSMIT = 0x02;
  static const int RESP_TYPE_COMPLETE = 0x03;
  static const int RESP_TYPE_ERROR = 0x04;

  // 最大数据长度
  static const int MAX_DATA_PER_PACKET = 244;
  static const int MAX_PACKETS = 65535;

  // 错误码
  static const int ERR_SUCCESS = 0;
  static const int ERR_CRC_MISMATCH = 1;
  static const int ERR_FRAME_FORMAT = 2;
  static const int ERR_BUFFER_FULL = 3;
  static const int ERR_TIMEOUT = 4;
  static const int ERR_PACKET_LOST = 5;

  /// CRC16计算 (XMODEM算法)
  static int calculateCrc16(List<int> data) {
    int crc = 0;
    for (int i = 0; i < data.length; i++) {
      crc ^= (data[i] & 0xFF) << 8;
      for (int j = 0; j < 8; j++) {
        if (crc & 0x8000 != 0) {
          crc = (crc << 1) ^ 0x1021; // XMODEM多项式
        } else {
          crc <<= 1;
        }
      }
    }
    return crc & 0xFFFF;
  }

  /// 创建命令帧
  static List<int> createCommandFrame(int type, int totalPackets, int packetIndex, List<int> data) {
    List<int> frame = [];
    
    // 添加帧头
    frame.add(FRAME_HEADER_CMD);
    
    // 添加命令类型
    frame.add(type);
    
    // 添加总包数 (2字节，小端序)
    frame.add(totalPackets & 0xFF);
    frame.add((totalPackets >> 8) & 0xFF);
    
    // 添加包序号 (2字节，小端序)
    frame.add(packetIndex & 0xFF);
    frame.add((packetIndex >> 8) & 0xFF);
    
    // 添加数据长度 (2字节，小端序)
    frame.add(data.length & 0xFF);
    frame.add((data.length >> 8) & 0xFF);
    
    // 添加数据
    frame.addAll(data);
    
    // 计算校验和 - 计算除了帧头和帧尾外的部分
    List<int> crcData = frame.sublist(1); // 不包括帧头
    int crc = calculateCrc16(crcData);
    
    // 添加校验和 (2字节，小端序)
    frame.add(crc & 0xFF);
    frame.add((crc >> 8) & 0xFF);
    
    // 添加帧尾
    frame.add(FRAME_TAIL_CMD);
    
    return frame;
  }

  /// 解析响应帧
  static Map<String, dynamic>? parseResponseFrame(List<int> data) {
    if (data.length < 9) return null; // 最小响应帧长度
    
    // 验证帧头帧尾
    if (data[0] != FRAME_HEADER_RESP || data[data.length - 1] != FRAME_TAIL_RESP) {
      return null;
    }
    
    // 计算校验和（type + packetIndex + info，均为小端序）
    List<int> crcData = data.sublist(1, data.length - 3); // 不包括帧头、校验和和帧尾
    int receivedCrc = data[data.length - 3] | (data[data.length - 2] << 8); // 小端序
    int calculatedCrc = calculateCrc16(crcData);
    
    if (receivedCrc != calculatedCrc) {
      return null; // CRC校验失败
    }
    
    return {
      'type': data[1],
      'packetIndex': data[2] | (data[3] << 8),   // 小端序
      'info': data[4] | (data[5] << 8),          // 小端序
    };
  }

  /// 分片发送大数据
  static Future<bool> sendLargeData(BluetoothCharacteristic writeChar, List<int> data, int type) async {
    // 检查特征属性，优先使用writeWithoutResponse，如果没有则使用write
    bool useWithoutResponse = writeChar.properties.writeWithoutResponse;
    bool useWithResponse = writeChar.properties.write;
    
    if (!useWithoutResponse && !useWithResponse) {
      print('错误：特征不支持write或writeWithoutResponse属性');
      return false;
    }
    
    // 打印特征属性信息，用于调试
    print('发送数据 - 特征属性检查:');
    print('  - write: $useWithResponse');
    print('  - writeWithoutResponse: $useWithoutResponse');
    print('  - 优先使用: ${useWithoutResponse ? "writeWithoutResponse" : "write"}');
    
    // 计算需要的包数
    int totalPackets = (data.length + MAX_DATA_PER_PACKET - 1) ~/ MAX_DATA_PER_PACKET;
    
    // 打印发送数据总览
    print('发送数据总览:');
    print('  - 数据类型: ${_getCommandTypeName(type)} (0x${type.toRadixString(16).padLeft(2, '0')})');
    print('  - 原始数据长度: ${data.length} 字节');
    print('  - 总包数: $totalPackets');
    print('  - 每包最大数据: $MAX_DATA_PER_PACKET 字节');
    
    for (int i = 0; i < totalPackets; i++) {
      // 计算当前包的数据范围
      int startIndex = i * MAX_DATA_PER_PACKET;
      int endIndex = (i + 1) * MAX_DATA_PER_PACKET;
      if (endIndex > data.length) endIndex = data.length;
      
      // 提取当前包数据
      List<int> packetData = data.sublist(startIndex, endIndex);
      
      // 创建命令帧
      List<int> frame = createCommandFrame(type, totalPackets, i, packetData);
      
      // 打印详细的帧内容
      _printFrameDetails(frame, i, totalPackets, type, packetData);
      
      // 发送数据
      try {
        // 优先使用writeWithoutResponse，避免连接超时
        await writeChar.write(frame, withoutResponse: useWithoutResponse);
        print('发送数据包 $i/$totalPackets (withoutResponse: $useWithoutResponse)');
        
        // 等待500ms确认
        await Future.delayed(const Duration(milliseconds: 500));
      } catch (e) {
        print('发送数据包失败: $e');
        // 简化重试机制：只重试1次，增加间隔避免GATT繁忙
        try {
          await Future.delayed(const Duration(milliseconds: 1000)); // 等待1秒
          // 重试时使用相反的write模式
          await writeChar.write(frame, withoutResponse: !useWithoutResponse);
          print('重试发送数据包 $i/$totalPackets (withoutResponse: ${!useWithoutResponse})');
          await Future.delayed(const Duration(milliseconds: 500));
        } catch (retryError) {
          print('重试失败: $retryError');
          return false; // 重试失败直接返回，避免多次重试导致连接断开
        }
      }
    }
    
    return true;
  }

  /// 获取命令类型名称
  static String _getCommandTypeName(int type) {
    switch (type) {
      case CMD_TYPE_DATA:
        return '数据命令';
      case CMD_TYPE_FILE:
        return '文件命令';
      case CMD_TYPE_CONTROL:
        return '控制命令';
      case CMD_TYPE_TIME_SYNC:
        return '时间同步命令';
      default:
        return '未知命令';
    }
  }

  /// 打印帧详细信息
  static void _printFrameDetails(List<int> frame, int packetIndex, int totalPackets, int type, List<int> packetData) {
    print('=== 数据包 $packetIndex/$totalPackets 详细信息 ===');
    print('命令类型: ${_getCommandTypeName(type)} (0x${type.toRadixString(16).padLeft(2, '0')})');
    print('帧总长度: ${frame.length} 字节');
    print('数据长度: ${packetData.length} 字节');
    
    // 打印帧结构分析
    print('帧结构分析:');
    print('  - 帧头: 0x${frame[0].toRadixString(16).padLeft(2, '0')}');
    print('  - 命令类型: 0x${frame[1].toRadixString(16).padLeft(2, '0')}');
    print('  - 总包数: ${frame[2] | (frame[3] << 8)} (小端序: 0x${frame[2].toRadixString(16).padLeft(2, '0')} 0x${frame[3].toRadixString(16).padLeft(2, '0')})');
    print('  - 包序号: ${frame[4] | (frame[5] << 8)} (小端序: 0x${frame[4].toRadixString(16).padLeft(2, '0')} 0x${frame[5].toRadixString(16).padLeft(2, '0')})');
    print('  - 数据长度: ${frame[6] | (frame[7] << 8)} (小端序: 0x${frame[6].toRadixString(16).padLeft(2, '0')} 0x${frame[7].toRadixString(16).padLeft(2, '0')})');
    
    // 打印数据内容（十六进制）
    print('数据内容 (十六进制):');
    String hexData = '';
    for (int i = 0; i < packetData.length; i++) {
      hexData += '${packetData[i].toRadixString(16).padLeft(2, '0')} ';
      if ((i + 1) % 16 == 0) {
        print('  $hexData');
        hexData = '';
      }
    }
    if (hexData.isNotEmpty) {
      print('  $hexData');
    }
    
    // 打印数据内容（ASCII，可打印字符）
    print('数据内容 (ASCII):');
    String asciiData = '';
    for (int i = 0; i < packetData.length; i++) {
      int byte = packetData[i];
      if (byte >= 32 && byte <= 126) {
        asciiData += String.fromCharCode(byte);
      } else {
        asciiData += '.';
      }
      if ((i + 1) % 16 == 0) {
        print('  $asciiData');
        asciiData = '';
      }
    }
    if (asciiData.isNotEmpty) {
      print('  $asciiData');
    }
    
    // 打印校验和和帧尾
    int crc = frame[frame.length - 3] | (frame[frame.length - 2] << 8);
    print('  - CRC校验和: 0x${crc.toRadixString(16).padLeft(4, '0')} (小端序: 0x${frame[frame.length - 3].toRadixString(16).padLeft(2, '0')} 0x${frame[frame.length - 2].toRadixString(16).padLeft(2, '0')})');
    print('  - 帧尾: 0x${frame[frame.length - 1].toRadixString(16).padLeft(2, '0')}');
    print('================================');
  }
}